use axum::{
    handler::Handler,
    http::StatusCode,
    middleware::{self},
    response::{Html, IntoResponse},
    routing::{get, post},
    Extension, Json, Router,
};
use tower::ServiceBuilder;
use tower_http::trace::TraceLayer;

use auth;
use config::CONFIG;
use cores::sessions;
use rbac;

/// Having a function that produces our app makes it easy to call it from tests
/// without having to create an HTTP server.
/// // build our application with a route
#[allow(dead_code)]
pub async fn app() -> Router {
    let rbac = rbac::RBAC::get_rbac(
        CONFIG.read().await.rbac_config().model_path(),
        CONFIG.read().await.rbac_config().database_url(),
    )
        .await;

    let session = sessions::Session::new("axum_test");

    Router::new()
        .nest(
            "/api",
            Router::new()
                .nest("/auth", auth::auth_server())
                .nest("/oauth2", auth::auth2_server())
                .nest("/rbac", rbac::rest_server()),
        )
        .route("/", get(handler))
        .route(
            "/json",
            post(|payload: Json<serde_json::Value>| async move {
                Json(serde_json::json!({ "data": payload.0 }))
            }),
        )
        .route_layer(middleware::from_extractor::<rbac::RBACMiddleware>())
        .layer(
            ServiceBuilder::new()
                .layer(TraceLayer::new_for_http())
                .layer(middleware::from_fn(sessions::session_middleware))
                .layer(middleware::from_fn(
                    super::middlewares::print_request_response,
                ))
                .layer(Extension(session))
                .layer(Extension(rbac)),
            // .layer(middleware::from_extractor::<rbac::RBACMiddleware>()),
        )
        // .fallback(handler_404.into_service())
    // 异常处理
}

async fn handler() -> Html<&'static str> {
    Html("<h1>Hello, World!</h1>")
}

async fn handler_404() -> impl IntoResponse {
    (StatusCode::NOT_FOUND, "NOT FOUND")
}
